<?php

class Weixin {

    private $_error;
    private $appid;
    private $appsecret;

    public function __construct() {
        $this->appid = Configure::get('weixin.appid');
        $this->appsecret = Configure::get('weixin.appsecret');
    }

    public function getAppId() {
        return $this->appid;
    }

    public function getUserInfo($access_token, $openid) {
        $data = [
            'access_token' => $access_token,
            'openid' => $openid,
            'lang' => 'zh_CN'
        ];
        $url = 'https://api.weixin.qq.com/sns/userinfo';
        $result = Curl::get($url, $data);
        $result = json_decode($result, true);
        if($result&&isset($result['openid']) && $result['openid']) {
            $user_info = [
                'openid' => $openid,
                'nickname' => $result['nickname'],
                'avatar' => $result['headimgurl'],
                'sex' => $result['sex']
            ];
            return $user_info;
        }
        $this->_error='获取用户信息失败,请稍后重试';
        return false;
    }
    
    public function getUserAccessToken($code) {
        if(!$code) {
            $this->_error = 'code不能为空,获取用户信息失败';
            return false;
        }
        $data = [
            'appid' => $this->appid,
            'secret' => $this->appsecret,
            'code' => $code,
            'grant_type' => 'authorization_code'
        ];
        $url = 'https://api.weixin.qq.com/sns/oauth2/access_token';
        $result = Curl::get($url, $data);
        if (!$result) {
            $this->_error = 'code值有误,获取用户信息失败';
            return false;
        }
        $result = json_decode($result, true);
        if ($result && isset($result['access_token']) && isset($result['openid'])) {
            return $result;
        }
        $this->_error = '获取用户信息失败,请重新登录';
        return false;
    }
    
    public function getAccessToken() {
        $accessToken = Cache_Memcache::getInstance()->get($this->appid.'accessToken');
        if ($accessToken) {
            return $accessToken;
        }
        return $this->_getAccessToken();
    }

    private function _getAccessToken() {
        $url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' . $this->appid . '&secret=' . $this->appsecret;
        $info = Curl::get($url);
        $info = json_decode($info, true);
        if (!$info) {
            $this->_error = '微信设置有误,获取access_token失败';
            return false;
        }
        if (isset($info['errcode'])) {
            $this->_error = '微信设置有误,' . $info['errcode'] . ':' . $info['errmsg'];
            return false;
        }
        if (isset($info['access_token']) && $info['access_token']) {
            Cache_Memcache::getInstance()->set($this->appid.'accessToken', $info['access_token'], 6000);
            return $info['access_token'];
        }
        $this->_error = '微信设置有误,获取ACCESS_TOKEN失败！';
        return false;
    }

    public function getJsTicket() {
        $jsTicket = Cache_Memcache::getInstance()->get($this->appid.'jsTicket');
        if ($jsTicket) {
            return $jsTicket;
        }
        return $this->_getJsTicket();
    }

    private function _getJsTicket() {
        $access_token = $this->getAccessToken();
        $url = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=' . $access_token . '&type=jsapi';
        $info = Curl::get($url);
        $info = json_decode($info, true);
        if (!$info) {
            $this->_error = '微信设置有误,获取jsapi_ticket失败';
            return false;
        }
        if (isset($info['ticket']) && $info['ticket']) {
            Cache_Memcache::getInstance()->set($this->appid.'jsTicket', $info['ticket'], 6000);
            return $info['ticket'];
        }
        $this->_error = '微信设置有误,获取jsapi_ticket失败！';
        return false;
    }

    public function getApiTicket() {
        $apiTicket = Cache_Memcache::getInstance()->get($this->appid.'apiTicket');
        if ($apiTicket) {
            return $apiTicket;
        }
        return $this->_getApiTicket();
    }

    private function _getApiTicket() {
        $url = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=' . $this->getAccessToken() . '&type=wx_card';
        $info = Curl::get($url);
        $info = json_decode($info, true);
        if (!$info) {
            $this->_error = '微信设置有误,获取api_ticket失败';
            return false;
        }
        if (isset($info['errcode']) && $info['errcode'] == 0) {
            Cache_Memcache::getInstance()->set($this->appid.'apiTicket', $info['ticket'], 6000);
            return $info['ticket'];
        }
        $this->_error = '微信设置有误,获取api_ticket失败！';
        return false;
    }

    function arrayToXml($arr) {
        $xml = "<xml>";
        foreach ($arr as $key => $val) {
            if (is_numeric($val)) {
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
            } else
                $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
        }
        $xml .= "</xml>";
        return $xml;
    }

    public function xmlToArray($xml) {
        libxml_disable_entity_loader(true);
        $array_data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        return $array_data;
    }

    public function json_encode_ch($data) {
        switch ($type = gettype($data)) {
            case 'NULL':
                return 'null';
            case 'boolean':
                return ($data ? 'true' : 'false');
            case 'integer':
            case 'double':
            case 'float':
                return $data;
            case 'string':
                return '"' . addslashes($data) . '"';
            case 'object':
                $data = get_object_vars($data);
            case 'array':
                $output_index_count = 0;
                $output_indexed = array();
                $output_associative = array();
                foreach ($data as $key => $value) {
                    $output_indexed[] = $this->json_encode_ch($value);
                    $output_associative[] = $this->json_encode_ch($key) . ':' . $this->json_encode_ch($value);
                    if ($output_index_count !== NULL && $output_index_count++ !== $key) {
                        $output_index_count = NULL;
                    }
                }
                if ($output_index_count !== NULL) {
                    return '[' . implode(',', $output_indexed) . ']';
                } else {
                    return '{' . implode(',', $output_associative) . '}';
                }
            default:
                return '';
        }
    }

    public function getError() {
        return $this->_error;
    }

    public function create_noncestr($length = 16) {
        $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        $len = strlen($chars);
        $str = "";
        for ($i = 0; $i < $length; $i++) {
            $str .= substr($chars, mt_rand(0, $len - 1), 1);
        }
        return $str;
    }

    public function getJsApi() {
        $from = isset($_SERVER['HTTP_REFERER'])?$_SERVER['HTTP_REFERER']:Configure::get('host.cdn');
        $pathArr = explode("#", $from);
        $url = $pathArr[0];
        $jsTicket = $this->getJsTicket();
        if (!$jsTicket) {
            return '';
        }
        $noncestr = $this->create_noncestr(10);
        $timestamp = (string) time();
        $data = array('jsapi_ticket=' . $jsTicket, 'noncestr=' . $noncestr, 'timestamp=' . $timestamp, 'url=' . $url);
        sort($data);
        $str = $data[0] . "&" . $data[1] . "&" . $data[2] . "&" . $data[3];
        $signature = sha1($str);
        $shareStr = '';
        $signData = array(
            "debug" => false,
            "appId" => $this->getAppId(),
            "timestamp" => $timestamp,
            "nonceStr" => $noncestr,
            "signature" => $signature
        );
        return $signData;
    }
    
    public function postTemplate($openId, $data, $template, $is_retry=true) {
        $url = 'https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=' . $this->getAccessToken();
        $postData = array(
            'touser' => $openId,
            'template_id' => $template['id']
        );
        if($template['url']) {
            $postData['url'] = $template['url'];
        }
        foreach ($template['data'] as $key => $val) {
            if (isset($data[$key])) {
                $template['data'][$key] = array();
                $template['data'][$key]['value'] = $data[$key];
            }
        }
        $postData['data'] = $template['data'];
        $result = Curl::post($url, $this->json_encode_ch($postData));
        $result = json_decode($result, true);
        if (!$result) {
            $this->_error = '微信设置有误,发送模板消息失败';
            return false;
        }
        if (isset($result['errcode']) && $result['errcode'] == 0) {
            return true;
        }
        if($is_retry) {
            $is_retry = false;
            Cache_Memcache::getInstance()->delete($this->appid.'accessToken');
            return $this->postTemplate($openId, $data, $template, $is_retry);
        }
        $this->_error = '微信设置有误,发送模板消息失败' . $result['errcode'];
        return false;
    }
    
    public function getTemplate() {
        $url = 'https://api.weixin.qq.com/cgi-bin/template/get_all_private_template?access_token=' . $this->getAccessToken();
        return Curl::get($url);
    }
    
    public function ToUrlParams($data) {
        $buff = '';
        foreach ($data as $k => $v) {
            if ($k != 'sign' && $v != '' && !is_array($v)) {
                $buff .= $k . '=' . $v . '&';
            }
        }
        $buff = trim($buff, '&');
        return $buff;
    }

    public function paySign($data, $key) {
        ksort($data);
        $string = $this->ToUrlParams($data);
        $string = $string . "&key=" . $key;
        $string = md5($string);
        $result = strtoupper($string);
        return $result;
    }

    public function postCurl($xml, $url, $useCert = false, $second = 30) {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_TIMEOUT, $second);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);

        curl_setopt($ch, CURLOPT_HEADER, FALSE);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        if ($useCert == true) {
            curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');
            curl_setopt($ch, CURLOPT_SSLCERT, APP_ROOT . '/application/config/apiclient_cert.pem');
            curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');
            curl_setopt($ch, CURLOPT_SSLKEY, APP_ROOT . '/application/config/apiclient_key.pem');
        }
        curl_setopt($ch, CURLOPT_POST, TRUE);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
        $data = curl_exec($ch);
        if ($data) {
            curl_close($ch);
            return $data;
        } else {
            $error = curl_errno($ch);
            curl_close($ch);
            $this->_error = "curl出错，错误码:$error";
            return false;
        }
    }

    private function filtterData($data) {
        foreach ($data as $k => $v) {
            if (!$v) {
                unset($data[$k]);
            }
        }
        return $data;
    }

}
